package config

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"github.com/spf13/viper"
)

var (
	config *Config
	once   sync.Once
)

// Load loads the configuration from file
func Load(configFile string) error {
	var err error
	once.Do(func() {
		v := viper.New()

		// Set default configuration file
		if configFile == "" {
			configFile = "config.yaml"
		}

		// Set default values
		setDefaults(v)

		// Read configuration file
		v.SetConfigFile(configFile)
		if err = v.ReadInConfig(); err != nil {
			return
		}

		// Read environment variables
		v.AutomaticEnv()

		// Unmarshal configuration
		config = &Config{}
		if err = v.Unmarshal(config); err != nil {
			return
		}

		// Validate configuration
		if err = validate(config); err != nil {
			return
		}
	})

	return err
}

// Get returns the configuration instance
func Get() *Config {
	if config == nil {
		panic("configuration not loaded")
	}
	return config
}

// Save saves the configuration to file
func Save(configFile string) error {
	if config == nil {
		return fmt.Errorf("configuration not loaded")
	}

	// Create configuration directory if not exists
	if err := os.MkdirAll(filepath.Dir(configFile), 0755); err != nil {
		return fmt.Errorf("failed to create config directory: %w", err)
	}

	// Marshal configuration to JSON
	data, err := json.MarshalIndent(config, "", "  ")
	if err != nil {
		return fmt.Errorf("failed to marshal config: %w", err)
	}

	// Write configuration to file
	if err := os.WriteFile(configFile, data, 0644); err != nil {
		return fmt.Errorf("failed to write config file: %w", err)
	}

	return nil
}

// setDefaults sets default configuration values
func setDefaults(v *viper.Viper) {
	// System defaults
	v.SetDefault("system.max_concurrent_tasks", 10)
	v.SetDefault("system.max_memory_usage", "1GB")
	v.SetDefault("system.max_cpu_usage", 80)
	v.SetDefault("system.log_level", "info")
	v.SetDefault("system.log_file", "xagent.log")

	// AI defaults
	v.SetDefault("ai.model", "gpt-4")
	v.SetDefault("ai.temperature", 0.7)
	v.SetDefault("ai.max_tokens", 2000)
	v.SetDefault("ai.timeout", 30)

	// Team defaults
	v.SetDefault("team.max_agents", 10)
	v.SetDefault("team.max_teams", 5)
	v.SetDefault("team.default_roles", []string{"planner", "coder", "reviewer"})

	// Server defaults
	v.SetDefault("server.host", "localhost")
	v.SetDefault("server.port", 8080)

	// Actor defaults
	v.SetDefault("actor.maxConcurrent", 10)
	v.SetDefault("actor.batchSize", 100)
	v.SetDefault("actor.queueSize", 1000)

	// Resource defaults
	v.SetDefault("resource.maxCPU", 0.8)
	v.SetDefault("resource.maxMemory", 0.8)
	v.SetDefault("resource.maxTasks", 100)

	// Monitoring defaults
	v.SetDefault("monitoring.enabled", true)

	// Security defaults
	v.SetDefault("security.encryption_enabled", false)
	v.SetDefault("security.auth_required", false)
	v.SetDefault("security.token_expiry", "24h")
}

// validate validates the configuration
func validate(cfg *Config) error {
	if cfg.System == nil || cfg.System.MaxConcurrentTasks < 1 {
		return fmt.Errorf("max_concurrent_tasks must be greater than 0")
	}

	if cfg.System.MaxCPUUsage < 0 || cfg.System.MaxCPUUsage > 100 {
		return fmt.Errorf("max_cpu_usage must be between 0 and 100")
	}

	if cfg.AI == nil || cfg.AI.MaxTokens < 1 {
		return fmt.Errorf("max_tokens must be greater than 0")
	}

	if cfg.AI.Timeout < 1 {
		return fmt.Errorf("timeout must be greater than 0")
	}

	if cfg.Team == nil || cfg.Team.MaxAgents < 1 {
		return fmt.Errorf("max_agents must be greater than 0")
	}

	if cfg.Team.MaxTeams < 1 {
		return fmt.Errorf("max_teams must be greater than 0")
	}

	if cfg.Server == nil || cfg.Server.Port < 0 || cfg.Server.Port > 65535 {
		return fmt.Errorf("invalid server port")
	}

	if cfg.Actor == nil || cfg.Actor.MaxConcurrent < 1 {
		return fmt.Errorf("invalid max concurrent")
	}

	if cfg.Resource == nil {
		return fmt.Errorf("resource configuration is required")
	}

	if cfg.Resource.MaxCPU < 0 || cfg.Resource.MaxCPU > 1 {
		return fmt.Errorf("invalid max CPU: %f", cfg.Resource.MaxCPU)
	}

	if cfg.Resource.MaxMemory < 0 || cfg.Resource.MaxMemory > 1 {
		return fmt.Errorf("invalid max memory: %f", cfg.Resource.MaxMemory)
	}

	return nil
}

// GetPrompt retrieves a prompt template for a specific role and task
func (c *Config) GetPrompt(role, task string) (string, error) {
	roleConfig, ok := c.Team.Roles[role]
	if !ok {
		return "", fmt.Errorf("no configuration found for role: %s", role)
	}

	prompt, ok := roleConfig.Prompts[task]
	if !ok {
		return "", fmt.Errorf("no prompt found for task %s in role %s", task, role)
	}

	return prompt, nil
}

// GetWorkspacePath returns the absolute path for a workspace item
func (c *Config) GetWorkspacePath(item string) string {
	return filepath.Join(c.System.WorkspaceDir, item)
}

// GetMetricsInterval returns the interval for a specific metric type
func (c *Config) GetMetricsInterval(metricType string) time.Duration {
	for _, metric := range c.Monitoring.Metrics {
		if strings.EqualFold(metric.Type, metricType) {
			return metric.Interval
		}
	}
	return 60 * time.Second // Default interval
}

// ToMap converts the configuration to a map
func (c *Config) ToMap() map[string]interface{} {
	return map[string]interface{}{
		"system": map[string]interface{}{
			"max_concurrent_tasks": c.System.MaxConcurrentTasks,
			"max_memory_usage":     c.System.MaxMemoryUsage,
			"max_cpu_usage":        c.System.MaxCPUUsage,
			"log_level":            c.System.LogLevel,
			"log_file":             c.System.LogFile,
			"workspace_dir":        c.System.WorkspaceDir,
			"num_engineers":        c.System.NumEngineers,
		},
		"ai": map[string]interface{}{
			"model":       c.AI.Model,
			"temperature": c.AI.Temperature,
			"max_tokens":  c.AI.MaxTokens,
			"timeout":     c.AI.Timeout,
			"provider":    c.AI.Provider,
			"api_key":     c.AI.APIKey,
			"options":     c.AI.Options,
		},
		"team": map[string]interface{}{
			"max_agents":    c.Team.MaxAgents,
			"max_teams":     c.Team.MaxTeams,
			"default_roles": c.Team.DefaultRoles,
			"roles":         c.Team.Roles,
		},
		"server": map[string]interface{}{
			"host": c.Server.Host,
			"port": c.Server.Port,
		},
		"actor": map[string]interface{}{
			"maxConcurrent": c.Actor.MaxConcurrent,
			"batchSize":     c.Actor.BatchSize,
			"queueSize":     c.Actor.QueueSize,
		},
		"resource": map[string]interface{}{
			"maxCPU":    c.Resource.MaxCPU,
			"maxMemory": c.Resource.MaxMemory,
			"maxTasks":  c.Resource.MaxTasks,
		},
		"monitoring": map[string]interface{}{
			"enabled": c.Monitoring.Enabled,
			"metrics": c.Monitoring.Metrics,
		},
		"security": map[string]interface{}{
			"encryption_enabled": c.Security.EncryptionEnabled,
			"auth_required":      c.Security.AuthRequired,
			"token_expiry":       c.Security.TokenExpiry,
		},
	}
}
